#include "U2GLESRenderTexture.h"

#include "U2GLESHardwarePixelBuffer.h"


U2EG_NAMESPACE_USING


template<> U2GLESRTTManager* U2Singleton<U2GLESRTTManager>::s_pSingleton = 0;

U2GLESRTTManager::~U2GLESRTTManager()
{
}

U2MultiRenderTarget* U2GLESRTTManager::createMultiRenderTarget(const U2String & name)
{
    // TODO: Check rendersystem capabilities before throwing the exception
    U2_EXCEPT(U2Exception::ERR_NOT_IMPLEMENTED,
                "MultiRenderTarget can only be used with GL_OES_framebuffer_object extension",
                "GLESRTTManager::createMultiRenderTarget");
}

PixelFormat U2GLESRTTManager::getSupportedAlternative(PixelFormat format)
{
    if (checkFormat(format))
    {
        return format;
    }

    /// Find first alternative
    PixelComponentType pct = U2PixelUtil::getComponentType(format);

    switch (pct)
    {
        case PCT_BYTE:
            format = PF_A8R8G8B8;
            break;
        case PCT_SHORT:
            format = PF_SHORT_RGBA;
            break;
        case PCT_FLOAT16:
            format = PF_FLOAT16_RGBA;
            break;
        case PCT_FLOAT32:
            format = PF_FLOAT32_RGBA;
            break;
        case PCT_COUNT:
        default:
            break;
    }

    if (checkFormat(format))
        return format;

    /// If none at all, return to default
    return PF_A8R8G8B8;
}

U2GLESRenderTexture::U2GLESRenderTexture(const U2String &name,
                                     const U2GLESSurfaceDesc &target,
                                     bool writeGamma,
                                     u2uint fsaa)
    : U2RenderTexture(target.buffer, target.zoffset)
{
    mName = name;
    mHwGamma = writeGamma;
    mFSAA = fsaa;
}

U2GLESRenderTexture::~U2GLESRenderTexture()
{
}

U2GLESCopyingRenderTexture::U2GLESCopyingRenderTexture(U2GLESCopyingRTTManager *manager,
                                                   const U2String &name,
                                                   const U2GLESSurfaceDesc &target,
                                                   bool writeGamma, u2uint fsaa)
    : U2GLESRenderTexture(name, target, writeGamma, fsaa)
{
}

void U2GLESCopyingRenderTexture::getCustomAttribute(const U2String& name, void* pData)
{
    if (name=="TARGET")
    {
        U2GLESSurfaceDesc &target = *static_cast<U2GLESSurfaceDesc*>(pData);
        target.buffer = static_cast<GLESHardwarePixelBuffer*>(mBuffer);
        target.zoffset = mZOffset;
    }
}

U2GLESCopyingRTTManager::U2GLESCopyingRTTManager()
{
}

U2GLESCopyingRTTManager::~U2GLESCopyingRTTManager()
{
}

U2RenderTexture *U2GLESCopyingRTTManager::createRenderTexture(const U2String &name,
                                                          const U2GLESSurfaceDesc &target,
                                                          bool writeGamma, u2uint fsaa)
{
    return U2_NEW U2GLESCopyingRenderTexture(this, name, target, writeGamma, fsaa);
}

bool U2GLESCopyingRTTManager::checkFormat(PixelFormat format)
{
    return true;
}

void U2GLESCopyingRTTManager::bind(U2RenderTarget *target)
{
    // Nothing to do here
}

void U2GLESCopyingRTTManager::unbind(U2RenderTarget *target)
{
    // Copy on unbind
    U2GLESSurfaceDesc surface;
    surface.buffer = 0;
    target->getCustomAttribute("TARGET", &surface);
    if (surface.buffer)
    {
        static_cast<GLESTextureBuffer*>(surface.buffer)->copyFromFramebuffer(surface.zoffset);
    }
}
